{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": [],
      "include_colab_link": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/nceder/qpb4e/blob/main/code/Chapter%2013/Chapter_13.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "# 13 Reading and writing files"
      ],
      "metadata": {
        "id": "j5RZrXkHmOEU"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "# 13.3 Opening files in write or other modes"
      ],
      "metadata": {
        "id": "NYNYihP7OsEe"
      }
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "YC8KD7B1O1Ex"
      },
      "source": [
        "file_object = open(\"myfile\", 'w')\n",
        "file_object.write(\"Hello, World\\n\")\n",
        "file_object.close()"
      ],
      "execution_count": 1,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "# 13.4 Functions to read and write text or binary data"
      ],
      "metadata": {
        "id": "uih_m9cbPAST"
      }
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "aYw0jt7RO1Ex",
        "outputId": "ac374d3a-21f5-4c12-de69-1b59636601a9",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "source": [
        "file_object = open(\"myfile\", 'r')\n",
        "count = 0\n",
        "while file_object.readline() != \"\":\n",
        "    count = count + 1\n",
        "print(count)\n",
        "file_object.close()"
      ],
      "execution_count": 2,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "1\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "_-li9jGFO1Ey",
        "outputId": "5d065f11-fa8c-4722-d38d-2827a91f45c0",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "source": [
        "file_object = open(\"myfile\", 'r')\n",
        "print(len(file_object.readlines()))\n",
        "file_object.close()"
      ],
      "execution_count": 3,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "1\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "gddwq_waO1Ey",
        "outputId": "0d40bb59-78ab-46ec-c57a-a5e896ac03b8",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "source": [
        "file_object = open(\"myfile\", 'r')\n",
        "count = 0\n",
        "for line in file_object:\n",
        "    count = count + 1\n",
        "print(count)\n",
        "file_object.close()"
      ],
      "execution_count": 4,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "1\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "6qPmdY-6O1Ey"
      },
      "source": [
        "input_file = open(\"myfile\", 'r')\n",
        "lines = input_file.readlines()\n",
        "input_file.close()\n",
        "output = open(\"myfile2.txt\", 'w')\n",
        "output.writelines(lines)\n",
        "output.close()"
      ],
      "execution_count": 7,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "## 13.4.1 Using binary mode"
      ],
      "metadata": {
        "id": "XXsNzbNyPKEC"
      }
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "_tvehZNtO1Ey"
      },
      "source": [
        "input_file = open(\"myfile\", 'rb')\n",
        "header = input_file.read(4)\n",
        "data = input_file.read()\n",
        "input_file.close()"
      ],
      "execution_count": 8,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "# 13.5 Reading and writing with pathlib"
      ],
      "metadata": {
        "id": "fbZLb7K3PWiA"
      }
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "P9kXS3YGO1Ey",
        "outputId": "7dd08398-06aa-4329-bcdc-0cc3c09580b9",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "source": [
        "from pathlib import Path\n",
        "p_text = Path('my_text_file')\n",
        "p_text.write_text('Text file contents')"
      ],
      "execution_count": 9,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "18"
            ]
          },
          "metadata": {},
          "execution_count": 9
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "GARTQuqbO1Ez",
        "outputId": "90a01b33-017d-42b0-fb7a-7a1e8f6ea9ea",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 35
        }
      },
      "source": [
        "p_text.read_text()"
      ],
      "execution_count": 10,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "'Text file contents'"
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            }
          },
          "metadata": {},
          "execution_count": 10
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "7ZXbH8Y6O1Ez",
        "outputId": "f21e9445-5382-4aff-f1c2-720319fb5aad",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "source": [
        "p_binary = Path('my_binary_file')\n",
        "p_binary.write_bytes(b'Binary file contents')"
      ],
      "execution_count": 11,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "20"
            ]
          },
          "metadata": {},
          "execution_count": 11
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "YH-YhBYgO1Ez",
        "outputId": "fb72fa71-4874-40fe-b04f-cd56dcf51aa4",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "source": [
        "p_binary.read_bytes()"
      ],
      "execution_count": 12,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "b'Binary file contents'"
            ]
          },
          "metadata": {},
          "execution_count": 12
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "# 13.6 Screen input/output and redirection"
      ],
      "metadata": {
        "id": "-o1Drh6sPj2q"
      }
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Z4m86e-NO1Ez",
        "outputId": "e3eca7bf-8478-4268-d236-04fb466600da",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "source": [
        "x = input(\"enter file name to use: \")"
      ],
      "execution_count": 13,
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "enter file name to use: myfile\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "11vn1h_0O1Ez",
        "outputId": "8c2659ef-3ed6-4ce4-ef4f-99ab8f21e32e",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 35
        }
      },
      "source": [
        "x"
      ],
      "execution_count": 14,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "'myfile'"
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            }
          },
          "metadata": {},
          "execution_count": 14
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "BwF1e9MQO1Ez",
        "outputId": "a28628d4-6e80-4902-d6c6-d4b87c0f7707",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "source": [
        "x = int(input(\"enter your number: \"))"
      ],
      "execution_count": 17,
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "enter your number: 39\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "aScIWTDVO1E0",
        "outputId": "3b139b20-4c5c-4f13-e741-d12ffbf907e3",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "source": [
        "x"
      ],
      "execution_count": 18,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "39"
            ]
          },
          "metadata": {},
          "execution_count": 18
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "XoTuxf7LO1E0",
        "outputId": "b358c4a7-b3fc-4223-c560-3bcab4cf3d25",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "source": [
        "import sys\n",
        "print(\"Write to the standard output.\")\n"
      ],
      "execution_count": 19,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Write to the standard output.\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "gFqZTad3O1E0",
        "outputId": "17c5f94f-dd09-4a96-b8af-19ccaed2d1fe",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "source": [
        "sys.stdout.write(\"Write to the standard output.\\n\")"
      ],
      "execution_count": 20,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Write to the standard output.\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Warning about Colaboratory and Jupyter\n",
        "\n",
        " Since Colaboratory (and Jupyter in general) takes more control of standard input and output, using `sys.__stdout__` for these examples (as shown in the book) won't work here as indicated; instead you need to save the old value of sys.stdout before changing it, and then restore the old value after using the redirected value.\n",
        "\n"
      ],
      "metadata": {
        "id": "lCu1LL3OP3H8"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "import sys\n",
        "f = open(\"outfile.txt\", 'w')\n",
        "old_sys_stdout = sys.stdout\n",
        "sys.stdout = f     #B\n",
        "sys.stdout.writelines([\"A first line.\\n\", \"A second line.\\n\"])  #C\n",
        "print(\"A line from the print function\") #C\n",
        "sys.stdout = old_sys_stdout\n",
        "f.close()\n",
        "! cat outfile.txt"
      ],
      "metadata": {
        "id": "BU7x4nidwYYq",
        "outputId": "9845506b-6e04-471b-ba3c-e966c009c241",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": 21,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "A first line.\n",
            "A second line.\n",
            "A line from the print function\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "f = open(\"outfile.txt\", 'w')  #A\n",
        "print(\"A first line.\\n\", \"A second line.\\n\", file=f)  #B\n",
        "f.close()\n",
        "\n",
        "!cat outfile.txt"
      ],
      "metadata": {
        "id": "10xvGB9aQ684",
        "outputId": "924d409e-72ef-4a3c-955c-73174aa46762",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": 22,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "A first line.\n",
            " A second line.\n",
            "\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Listing 13.1 File mio.py"
      ],
      "metadata": {
        "id": "EaRSijCgRT0i"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "```python\n",
        "\n",
        "\"\"\"mio: module, (contains functions capture_output, restore_output,\n",
        "     print_file, and clear_file )\"\"\"\n",
        "import sys\n",
        "_file_object = None\n",
        "def capture_output(file=\"capture_file.txt\"):\n",
        "    \"\"\"capture_output(file='capture_file.txt'): redirect the standard\n",
        "    output to 'file'.\"\"\"\n",
        "    global _file_object\n",
        "    print(\"output will be sent to file: {0}\".format(file))\n",
        "    print(\"restore to normal by calling 'mio.restore_output()'\")\n",
        "    _file_object = open(file, 'w')\n",
        "    sys.stdout = _file_object\n",
        "\n",
        "def restore_output():\n",
        "    \"\"\"restore_output(): restore the standard output back to the\n",
        "             default (also closes the capture file)\"\"\"\n",
        "    global _file_object\n",
        "    sys.stdout = sys.__stdout__\n",
        "    _file_object.close()\n",
        "    print(\"standard output has been restored back to normal\")\n",
        "\n",
        "def print_file(file=\"capture_file.txt\"):\n",
        "    \"\"\"print_file(file=\"capture_file.txt\"): print the given file to the\n",
        "         standard output\"\"\"\n",
        "    f = open(file, 'r')\n",
        "    print(f.read())\n",
        "    f.close()\n",
        "\n",
        "def clear_file(file=\"capture_file.txt\"):\n",
        "    \"\"\"clear_file(file=\"capture_file.txt\"): clears the contents of the\n",
        "         given file\"\"\"\n",
        "    f = open(file, 'w')\n",
        "    f.close()\n",
        "```"
      ],
      "metadata": {
        "id": "6h_9kCxgRdwr"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Execute the cell below to write the code to `mio.py`.**"
      ],
      "metadata": {
        "id": "k1bST4Jy7UUx"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "%%writefile mio.py\n",
        "\"\"\"mio: module, (contains functions capture_output, restore_output,\n",
        "     print_file, and clear_file )\"\"\"\n",
        "import sys\n",
        "_file_object = None\n",
        "def capture_output(file=\"capture_file.txt\"):\n",
        "    \"\"\"capture_output(file='capture_file.txt'): redirect the standard\n",
        "    output to 'file'.\"\"\"\n",
        "    global _file_object\n",
        "    print(\"output will be sent to file: {0}\".format(file))\n",
        "    print(\"restore to normal by calling 'mio.restore_output()'\")\n",
        "    _file_object = open(file, 'w')\n",
        "    sys.stdout = _file_object\n",
        "\n",
        "def restore_output():\n",
        "    \"\"\"restore_output(): restore the standard output back to the\n",
        "             default (also closes the capture file)\"\"\"\n",
        "    global _file_object\n",
        "    sys.stdout = sys.__stdout__\n",
        "    _file_object.close()\n",
        "    print(\"standard output has been restored back to normal\")\n",
        "\n",
        "def print_file(file=\"capture_file.txt\"):\n",
        "    \"\"\"print_file(file=\"capture_file.txt\"): print the given file to the\n",
        "         standard output\"\"\"\n",
        "    f = open(file, 'r')\n",
        "    print(f.read())\n",
        "    f.close()\n",
        "\n",
        "def clear_file(file=\"capture_file.txt\"):\n",
        "    \"\"\"clear_file(file=\"capture_file.txt\"): clears the contents of the\n",
        "         given file\"\"\"\n",
        "    f = open(file, 'w')\n",
        "    f.close()\n"
      ],
      "metadata": {
        "id": "6PVmfiCf7CfK",
        "outputId": "532494e2-3ec6-4daa-95d3-77256bd58646",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": 23,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Writing mio.py\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Try This: Redirecting output\n",
        "\n",
        "Write some code to use the `mio.py` module in listing 13.1 to capture all the print output of a script to a file named `myfile.txt`, reset the standard output to the screen, and print that file to screen.\n",
        "\n",
        "**Note:** This will not work with Colaboratory or Jupyter notebooks unless you write the code for `mio.py` and your test code to Python files, and then execute your file using the ! prefix. The cell above that will write `mio.py` to a Python file."
      ],
      "metadata": {
        "id": "8ebFQ_gBlrUZ"
      }
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "8-P5-2jNmHf7"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# @title\n",
        "# mio_test.py\n",
        "\n",
        "import mio\n",
        "\n",
        "def main():\n",
        "    mio.capture_output(\"myfile.txt\")\n",
        "    print(\"hello\")\n",
        "    print(1 + 3)\n",
        "    mio.restore_output()\n",
        "\n",
        "    mio.print_file(\"myfile.txt\")\n",
        "\n",
        "\n",
        "if __name__ == '__main__':\n",
        "    main()\n",
        "\n"
      ],
      "metadata": {
        "cellView": "form",
        "id": "mF2R5JsfTysU"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "# 13.7 Handling structured binary data with the struct module"
      ],
      "metadata": {
        "id": "Doh0jdZDRxja"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "import struct\n",
        "record_format = 'hd7s'\n",
        "data_record = struct.pack(record_format, 42, 3.14, b'goodbye')\n",
        "with open(\"data\", \"wb\") as data_file:\n",
        "    data_file.write(data_record)\n",
        "\n",
        "data_record"
      ],
      "metadata": {
        "id": "ZWnxEdzvSACM",
        "outputId": "4285cb78-7417-410c-8414-df293a5db035",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "b'*\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x1f\\x85\\xebQ\\xb8\\x1e\\t@goodbye'"
            ]
          },
          "metadata": {},
          "execution_count": 11
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "yLl7tW2bO1E1",
        "outputId": "6fa51923-40ed-4bfa-915d-7ae895391430",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "source": [
        "import struct\n",
        "\n",
        "record_format = 'hd7s'\n",
        "record_size = struct.calcsize(record_format)\n",
        "result_list = []\n",
        "with open(\"data\", 'rb') as input:\n",
        "    while True:\n",
        "        record = input.read(record_size)  #A\n",
        "        if not record:  #B\n",
        "            break\n",
        "        result_list.append(struct.unpack(record_format, record))  #C\n",
        "\n",
        "print(result_list)"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "[(42, 3.14, b'goodbye')]\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "# 13.8 Pickling objects to files"
      ],
      "metadata": {
        "id": "ETStmi44SgHn"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "import pickle\n",
        "a = 42\n",
        "b = 3.14\n",
        "c = \"test\"\n",
        "file = open(\"state\", 'wb')\n",
        "pickle.dump(a, file)\n",
        "pickle.dump(b, file)\n",
        "pickle.dump(c, file)\n",
        "file.close()"
      ],
      "metadata": {
        "id": "_RbrmHLWSnGe"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Fwvsta5DO1E1",
        "outputId": "6388d4c3-7411-40c1-b713-08b15bd522c1",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "source": [
        "import pickle\n",
        "file = open(\"state\", 'rb')\n",
        "a = pickle.load(file)\n",
        "b = pickle.load(file)\n",
        "c = pickle.load(file)\n",
        "file.close()\n",
        "print(f\"{a=} {b=} {c=}\")"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "a=42 b=3.14 c='test'\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "import pickle\n",
        "\n",
        "def save_data(data_dict):\n",
        "    with open(\"state\", 'wb') as file:\n",
        "        pickle.dump(data_dict, file)\n",
        "\n",
        "def restore_data():\n",
        "    with open(\"state\", 'rb') as file:\n",
        "        data_dict = pickle.load(file)\n",
        "    return data_dict\n",
        "\n",
        "if __name__ == '__main__':\n",
        "    data_dict = {'a': 42,\n",
        "                'b': 3.14,\n",
        "                'c': \"test\"\n",
        "                }\n",
        "    save_data(data_dict)\n",
        "    restored_data = restore_data()\n",
        "    print(restored_data)"
      ],
      "metadata": {
        "id": "4O18117jSuH9",
        "outputId": "82250325-1492-4a6f-d29f-eb501aca8e02",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "{'a': 42, 'b': 3.14, 'c': 'test'}\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Listing 13.2 File sole.py"
      ],
      "metadata": {
        "id": "Xy1GWcVpS15I"
      }
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "0pQRayxJO1E1"
      },
      "source": [
        "\"\"\"sole module: contains functions sole, save, show\"\"\"\n",
        "import pickle\n",
        "_sole_mem_cache_d = {}\n",
        "_sole_disk_file_s = \"solecache\"\n",
        "file = open(_sole_disk_file_s, 'rb')          #A\n",
        "_sole_mem_cache_d = pickle.load(file)\n",
        "file.close()\n",
        "\n",
        "def sole(m, n, t):                            #B\n",
        "    \"\"\"sole(m, n, t): perform the sole calculation using the cache.\"\"\"\n",
        "    global _sole_mem_cache_d\n",
        "    if (m, n, t) in _sole_mem_cache_d:\n",
        "        return _sole_mem_cache_d[(m, n, t)]\n",
        "    else:\n",
        "        # . . . do some time-consuming calculations . . .\n",
        "        result = f\"{m=}, {n=}, {t=}\"   #C\n",
        "        _sole_mem_cache_d[(m, n, t)] = result\n",
        "        return result\n",
        "\n",
        "def save():\n",
        "    \"\"\"save(): save the updated cache to disk.\"\"\"\n",
        "    global _sole_mem_cache_d, _sole_disk_file_s\n",
        "    file = open(_sole_disk_file_s, 'wb')\n",
        "    pickle.dump(_sole_mem_cache_d, file)\n",
        "    file.close()\n",
        "\n",
        "def show():\n",
        "    \"\"\"show(): print the cache\"\"\"\n",
        "    global _sole_mem_cache_d\n",
        "    print(_sole_mem_cache_d)"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "_Ak-p6PTO1E2"
      },
      "source": [
        "# TO CREATE CACHE FILE - execute before using above\n",
        "\n",
        "import pickle\n",
        "file = open(\"solecache\",'wb')\n",
        "pickle.dump({}, file)\n",
        "file.close()"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# Experiments with sole.py\n",
        "sole(1, 2, 3)\n",
        "sole(11, 22, 33)\n",
        "show()\n",
        "save()\n"
      ],
      "metadata": {
        "id": "FIJ_oaG4TRTT",
        "outputId": "823e30c8-f85f-463c-8b30-dd86040b9122",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "{(1, 2, 3): 'm=1, n=2, t=3', (11, 22, 33): 'm=11, n=22, t=33'}\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "# 13.9 Shelving objects"
      ],
      "metadata": {
        "id": "vAwIoI-wTsDa"
      }
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "SS_hjJMEO1E2"
      },
      "source": [
        "import shelve\n",
        "book = shelve.open(\"addresses\")"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "gyHVq7ybO1E2"
      },
      "source": [
        "book['flintstone'] = ('fred', '555-1234', '1233 Bedrock Place')\n",
        "book['rubble'] = ('barney', '555-4321', '1235 Bedrock Place')"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "rAGzmd5TO1E2"
      },
      "source": [
        "book.close()"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "ptwVhRSSO1E3"
      },
      "source": [
        "import shelve\n",
        "book = shelve.open(\"addresses\")"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "5B92C7prO1E3",
        "outputId": "a482e00c-a781-4ad7-f701-7a67cade8d6d",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "source": [
        "book['flintstone']"
      ],
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "('fred', '555-1234', '1233 Bedrock Place')"
            ]
          },
          "metadata": {},
          "execution_count": 26
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "# Lab 13: Final fixes to wc\n",
        "One thing that the wc utilty can do that our current Python version can't is handle input redirection, which is common particularly in Linux/Unix commandline environements. Refactor your existing Python version to handle redirection. That is, if a file is given as a command line argument, the utility should read from and process that file, but if no file argument is given, it should read from and process `stdin`.  For example with a file name:\n",
        "```\n",
        "! python wc_redirect.py wc_redirect.py   #A\n",
        "```\n",
        "```\n",
        "62  182 2058 wc_redirect.py\n",
        "```\n",
        "With redirection (no file name):\n",
        "```\n",
        "! python wc_redirect.py < wc_redirect.py  #B\n",
        "```\n",
        "```\n",
        " 62  182 2058\n",
        "```\n",
        "\n",
        "HINT: if you use the argparse library you need to be able to handle both having and not having an argument for the input filename, since if the input is coming via redirection argparse will not have a filename. To deal with this, look at the argparse documentation for `nargs` at https://docs.python.org/3/library/argparse.html#nargs and particularly the `?` options.\n"
      ],
      "metadata": {
        "id": "kHYZ7QQxIhab"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Author's solution\n",
        "\n",
        "Execute cell below to save to file `wc_redirect.py`."
      ],
      "metadata": {
        "id": "q48BLPJyKuoi"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# @title\n",
        "open(\"wc_redirect.py\", \"w\").write('''#!/usr/bin/env python3\n",
        "# File: wc_redirect.py\n",
        "\"\"\" Reads a file and returns the number of lines, words,\n",
        "    and characters - similar to the UNIX wc utility\n",
        "\"\"\"\n",
        "import sys\n",
        "import argparse\n",
        "\n",
        "\n",
        "def main():\n",
        "    # initialze counts\n",
        "    line_count = 0\n",
        "    word_count = 0\n",
        "    char_count = 0\n",
        "    byte_count = 0\n",
        "    longest_line = 0\n",
        "\n",
        "    parser = argparse.ArgumentParser(usage=__doc__)\n",
        "    parser.add_argument(\"-c\", \"--chars\",\n",
        "                  action=\"store_true\", dest=\"chars\", default=False,\n",
        "                  help=\"display number of characters\")\n",
        "    parser.add_argument(\"-w\", \"--words\",\n",
        "                  action=\"store_true\", dest=\"words\", default=False,\n",
        "                  help=\"display number of words\")\n",
        "    parser.add_argument(\"-l\", \"--lines\",\n",
        "                  action=\"store_true\", dest=\"lines\", default=False,\n",
        "                  help=\"display number of lines\")\n",
        "    parser.add_argument(\"-L\", \"--longest\",\n",
        "                  action=\"store_true\", dest=\"longest\", default=False,\n",
        "                  help=\"display longest line length\")\n",
        "    parser.add_argument(\"file\", nargs='?', type=argparse.FileType('r'), #A\n",
        "                        default=sys.stdin,   #B\n",
        "                        help=\"read data from this file\")\n",
        "    args = parser.parse_args()\n",
        "\n",
        "    with  args.file  as infile:\n",
        "        for line in infile.readlines():   #C\n",
        "            line_count += 1\n",
        "            char_count += len(line)\n",
        "            words = line.split()\n",
        "            word_count += len(words)\n",
        "            if len(line) > longest_line:\n",
        "                longest_line = len(line)\n",
        "\n",
        "    default_args = any([getattr(args, _) for _ in ('chars', 'words', 'lines', 'longest')])\n",
        "\n",
        "    if not default_args:\n",
        "        args.chars = args.lines = args.words = True\n",
        "\n",
        "    if args.lines:\n",
        "        print(f\"{line_count:3}\", end=\" \")\n",
        "    if args.words:\n",
        "        print(f\"{word_count:4}\", end=\" \")\n",
        "    if args.chars:\n",
        "        print(f\"{char_count:4}\", end=\" \")\n",
        "    if args.longest:\n",
        "        print(f'{longest_line}', end=\" \")\n",
        "    if args.file.name != '<stdin>':      #D\n",
        "        print(f'{args.file.name}', end=\" \")\n",
        "    print()\n",
        "\n",
        "if __name__ == '__main__':\n",
        "    main()\n",
        "    ''')"
      ],
      "metadata": {
        "cellView": "form",
        "id": "wSm8mikEhlIq",
        "outputId": "98387954-a9f0-4c5b-a0b5-ca673b2b8d8a",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "2095"
            ]
          },
          "metadata": {},
          "execution_count": 25
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "#!/usr/bin/env python3\n",
        "# File: wc_redirect.py\n",
        "\"\"\" Reads a file and returns the number of lines, words,\n",
        "    and characters - similar to the UNIX wc utility\n",
        "\"\"\"\n",
        "import sys\n",
        "import argparse\n",
        "\n",
        "\n",
        "def main():\n",
        "    # initialze counts\n",
        "    line_count = 0\n",
        "    word_count = 0\n",
        "    char_count = 0\n",
        "    byte_count = 0\n",
        "    longest_line = 0\n",
        "\n",
        "    parser = argparse.ArgumentParser(usage=__doc__)\n",
        "    parser.add_argument(\"-c\", \"--chars\",\n",
        "                  action=\"store_true\", dest=\"chars\", default=False,\n",
        "                  help=\"display number of characters\")\n",
        "    parser.add_argument(\"-w\", \"--words\",\n",
        "                  action=\"store_true\", dest=\"words\", default=False,\n",
        "                  help=\"display number of words\")\n",
        "    parser.add_argument(\"-l\", \"--lines\",\n",
        "                  action=\"store_true\", dest=\"lines\", default=False,\n",
        "                  help=\"display number of lines\")\n",
        "    parser.add_argument(\"-L\", \"--longest\",\n",
        "                  action=\"store_true\", dest=\"longest\", default=False,\n",
        "                  help=\"display longest line length\")\n",
        "    parser.add_argument(\"file\", nargs='?', type=argparse.FileType('r'), #A\n",
        "                        default=sys.stdin,   #B\n",
        "                        help=\"read data from this file\")\n",
        "    args = parser.parse_args()\n",
        "\n",
        "    with  args.file  as infile:\n",
        "        for line in infile.readlines():   #C\n",
        "            line_count += 1\n",
        "            char_count += len(line)\n",
        "            words = line.split()\n",
        "            word_count += len(words)\n",
        "            if len(line) > longest_line:\n",
        "                longest_line = len(line)\n",
        "\n",
        "    default_args = any([getattr(args, _) for _ in ('chars', 'words', 'lines', 'longest')])\n",
        "\n",
        "    if not default_args:\n",
        "        args.chars = args.lines = args.words = True\n",
        "\n",
        "    if args.lines:\n",
        "        print(f\"{line_count:3}\", end=\" \")\n",
        "    if args.words:\n",
        "        print(f\"{word_count:4}\", end=\" \")\n",
        "    if args.chars:\n",
        "        print(f\"{char_count:4}\", end=\" \")\n",
        "    if args.longest:\n",
        "        print(f'{longest_line}', end=\" \")\n",
        "    if args.file.name != '<stdin>':      #D\n",
        "        print(f'{args.file.name}', end=\" \")\n",
        "    print()\n",
        "\n",
        "if __name__ == '__main__':\n",
        "    main()"
      ],
      "metadata": {
        "id": "ycsqAXokJlkP"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "! python wc_redirect.py -l -w -c -L < wc_redirect.py"
      ],
      "metadata": {
        "id": "X9FPiKPnhxhq",
        "outputId": "1bef49d9-4e3d-4282-f2f6-e533e0618df5",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            " 64  186 2095 91 \n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Copilot's solution\n",
        "\n",
        "### Prompt:\n",
        "\n",
        "Refactor the current file `wc_coplilot.py` to make the script support input/output redirection. Output should be similar to that of `wc` utility.\n",
        "\n",
        "Execute cell below to save `wc_redirect_copilot.py` to disk."
      ],
      "metadata": {
        "id": "fCll0kxlXEhB"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# @title\n",
        "open(\"wc_redirect_copilot.py\", \"w\").write(\"\"\"# wc_copilot.py\n",
        "\n",
        "import argparse\n",
        "import sys\n",
        "\n",
        "def count_stats(file):\n",
        "    lines = file.readlines()\n",
        "\n",
        "    line_count = len(lines)\n",
        "    word_count = sum(len(line.split()) for line in lines)\n",
        "    char_count = sum(len(line) for line in lines)\n",
        "    max_line_length = max(len(line) for line in lines)\n",
        "\n",
        "    return line_count, word_count, char_count, max_line_length\n",
        "\n",
        "def main():\n",
        "    parser = argparse.ArgumentParser(description='Count lines, words, and characters in a file.')\n",
        "    parser.add_argument('file', nargs='?', type=argparse.FileType('r'), #A\n",
        "                         default=sys.stdin, help='File to count')\n",
        "    parser.add_argument('-l', '--lines', action='store_true', help='Count lines')\n",
        "    parser.add_argument('-w', '--words', action='store_true', help='Count words')\n",
        "    parser.add_argument('-c', '--chars', action='store_true', help='Count characters')\n",
        "    parser.add_argument('-L', '--max-line-length', action='store_true', help='Print length of the longest line')\n",
        "    args = parser.parse_args()\n",
        "\n",
        "    line_count, word_count, char_count, max_line_length = count_stats(args.file)\n",
        "\n",
        "    output = []\n",
        "    if args.lines:\n",
        "        output.append(str(line_count))\n",
        "    if args.words:\n",
        "        output.append(str(word_count))\n",
        "    if args.chars:\n",
        "        output.append(str(char_count))\n",
        "    if args.max_line_length:\n",
        "        output.append(str(max_line_length))\n",
        "\n",
        "    print(' '.join(output))\n",
        "\n",
        "if __name__ == '__main__':\n",
        "    main()\n",
        "\"\"\")"
      ],
      "metadata": {
        "id": "O3ZMqhTnlB1n",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "cellView": "form",
        "outputId": "4394d3f0-7888-4bd3-db67-901a78f3b063"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "1414"
            ]
          },
          "metadata": {},
          "execution_count": 18
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# wc_redirect_copilot.py\n",
        "\n",
        "import argparse\n",
        "import sys\n",
        "\n",
        "def count_stats(file):\n",
        "    lines = file.readlines()\n",
        "\n",
        "    line_count = len(lines)\n",
        "    word_count = sum(len(line.split()) for line in lines)\n",
        "    char_count = sum(len(line) for line in lines)\n",
        "    max_line_length = max(len(line) for line in lines)\n",
        "\n",
        "    return line_count, word_count, char_count, max_line_length\n",
        "\n",
        "def main():\n",
        "    parser = argparse.ArgumentParser(description='Count lines, words, and characters in a file.')\n",
        "    parser.add_argument('file', nargs='?', type=argparse.FileType('r'), #A\n",
        "                         default=sys.stdin, help='File to count')\n",
        "    parser.add_argument('-l', '--lines', action='store_true', help='Count lines')\n",
        "    parser.add_argument('-w', '--words', action='store_true', help='Count words')\n",
        "    parser.add_argument('-c', '--chars', action='store_true', help='Count characters')\n",
        "    parser.add_argument('-L', '--max-line-length', action='store_true', help='Print length of the longest line')\n",
        "    args = parser.parse_args()\n",
        "\n",
        "    line_count, word_count, char_count, max_line_length = count_stats(args.file)\n",
        "\n",
        "    output = []\n",
        "    if args.lines:\n",
        "        output.append(str(line_count))\n",
        "    if args.words:\n",
        "        output.append(str(word_count))\n",
        "    if args.chars:\n",
        "        output.append(str(char_count))\n",
        "    if args.max_line_length:\n",
        "        output.append(str(max_line_length))\n",
        "\n",
        "    print(' '.join(output))\n",
        "\n",
        "if __name__ == '__main__':\n",
        "    main()"
      ],
      "metadata": {
        "id": "S2A6U3WrfdZT"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "! python wc_redirect_copilot.py -l -w -c -L wc_redirect_copilot.py"
      ],
      "metadata": {
        "id": "an4GK6Hfe-ma",
        "outputId": "b5ff9e43-6509-40a9-d92b-9f5248a5df06",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "41 115 1414 113\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Colaboratory's solution\n",
        "\n",
        "### Prompt:\n",
        "\n",
        "Refactor the cell above to make the script support input/output\n",
        "redirection. Output should be similar to that of wc utility.\n",
        "\n",
        "\n",
        "Execute cell below to save `wc_redirect_colab.py` to disk."
      ],
      "metadata": {
        "id": "tGuhYlKGXLgw"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# @title\n",
        "open(\"wc_redirect_colab.py\", \"w\").write('''# prompt: Refactor the cell above to make the script support input/output\n",
        "#         redirection. Output should be similar to that of wc utility.\n",
        "\n",
        "import argparse\n",
        "import sys\n",
        "\n",
        "\"\"\" Reads a file and returns the number of lines, words,\n",
        "    and characters - similar to the UNIX wc utility\n",
        "\"\"\"\n",
        "\n",
        "\n",
        "def main():\n",
        "    parser = argparse.ArgumentParser(usage=__doc__)\n",
        "    parser.add_argument(\"filename\", nargs='*')   #A\n",
        "    parser.add_argument(\"-l\", \"--lines\", dest=\"lines\",\n",
        "                      action='store_true', default=False,\n",
        "                      help=\"Show only line count\")\n",
        "    parser.add_argument(\"-w\", \"--words\", dest=\"words\",\n",
        "                      action='store_true', default=False,\n",
        "                      help=\"Show only word count\")\n",
        "    parser.add_argument(\"-c\", \"--chars\", dest=\"chars\",\n",
        "                      action='store_true', default=False,\n",
        "                      help=\"Show only character count\")\n",
        "    parser.add_argument(\"-L\", \"--longest\", dest=\"longest\",\n",
        "                      action='store_true', default=False,\n",
        "                      help=\"Show length of longest line\")\n",
        "    args = parser.parse_args()\n",
        "\n",
        "    if not sys.stdin.isatty():    #B\n",
        "        # Read from standard input\n",
        "        lines = sys.stdin.readlines()\n",
        "    else:\n",
        "        for filename in args.filename:  #C\n",
        "            with open(filename) as infile:\n",
        "                lines = infile.readlines()\n",
        "\n",
        "    line_count = len(lines)\n",
        "    word_count = sum(len(line.split()) for line in lines)\n",
        "    char_count = sum(len(line) for line in lines)\n",
        "    longest_line_length = max(len(line) for line in lines)\n",
        "\n",
        "    if args.lines:\n",
        "        print(f\"{line_count}\")\n",
        "    elif args.words:\n",
        "        print(f\"{word_count}\")\n",
        "    elif args.chars:\n",
        "        print(f\"{char_count}\")\n",
        "    elif args.longest:\n",
        "        print(f\"{longest_line_length}\")\n",
        "    else:\n",
        "        print(f\"{line_count} {word_count} {char_count}\")\n",
        "\n",
        "if __name__ == '__main__':\n",
        "    main()\n",
        "    ''')"
      ],
      "metadata": {
        "cellView": "form",
        "id": "XgP-CGTQfxP3",
        "outputId": "d9905efb-9458-4505-ee52-d03dc127446e",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "1882"
            ]
          },
          "metadata": {},
          "execution_count": 12
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# prompt: Refactor the cell above to make the script support input/output\n",
        "#         redirection. Output should be similar to that of wc utility.\n",
        "\n",
        "import argparse\n",
        "import sys\n",
        "\n",
        "\"\"\" Reads a file and returns the number of lines, words,\n",
        "    and characters - similar to the UNIX wc utility\n",
        "\"\"\"\n",
        "\n",
        "\n",
        "def main():\n",
        "    parser = argparse.ArgumentParser(usage=__doc__)\n",
        "    parser.add_argument(\"filename\", nargs='*')   #A\n",
        "    parser.add_argument(\"-l\", \"--lines\", dest=\"lines\",\n",
        "                      action='store_true', default=False,\n",
        "                      help=\"Show only line count\")\n",
        "    parser.add_argument(\"-w\", \"--words\", dest=\"words\",\n",
        "                      action='store_true', default=False,\n",
        "                      help=\"Show only word count\")\n",
        "    parser.add_argument(\"-c\", \"--chars\", dest=\"chars\",\n",
        "                      action='store_true', default=False,\n",
        "                      help=\"Show only character count\")\n",
        "    parser.add_argument(\"-L\", \"--longest\", dest=\"longest\",\n",
        "                      action='store_true', default=False,\n",
        "                      help=\"Show length of longest line\")\n",
        "    args = parser.parse_args()\n",
        "\n",
        "    if not sys.stdin.isatty():    #B\n",
        "        # Read from standard input\n",
        "        lines = sys.stdin.readlines()\n",
        "    else:\n",
        "        for filename in args.filename:  #C\n",
        "            with open(filename) as infile:\n",
        "                lines = infile.readlines()\n",
        "\n",
        "    line_count = len(lines)\n",
        "    word_count = sum(len(line.split()) for line in lines)\n",
        "    char_count = sum(len(line) for line in lines)\n",
        "    longest_line_length = max(len(line) for line in lines)\n",
        "\n",
        "    if args.lines:\n",
        "        print(f\"{line_count}\")\n",
        "    elif args.words:\n",
        "        print(f\"{word_count}\")\n",
        "    elif args.chars:\n",
        "        print(f\"{char_count}\")\n",
        "    elif args.longest:\n",
        "        print(f\"{longest_line_length}\")\n",
        "    else:\n",
        "        print(f\"{line_count} {word_count} {char_count}\")\n",
        "\n",
        "if __name__ == '__main__':\n",
        "    main()"
      ],
      "metadata": {
        "id": "h-tmhjz4rDqe"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "! python wc_redirect_colab.py -l -w -c -L < wc_redirect_colab.py"
      ],
      "metadata": {
        "id": "l0ePIbJGgazd",
        "outputId": "32409ede-8910-4e61-acf5-14338927afc5",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "55\n"
          ]
        }
      ]
    }
  ]
}